package offer;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;

import com.netscenery.yang.designer.Action;
import com.netscenery.yang.model.Import;
import com.netscenery.yang.model.Include;
import com.netscenery.yang.model.MainModule;
import com.netscenery.yang.model.Module;
import com.netscenery.yang.model.Node;
import com.netscenery.yang.model.SubModule;
import com.netscenery.yang.model.BuiltinType;
import com.netscenery.yang.writer.YangFormatter;

import offer.system.ModuleStatus;
import system.bean.DocRelation;
import system.bean.Member;
import system.bean.ModuleDocument;
import system.bean.ModuleFile;
import system.dao.DocumentDao;



public class GetDataSource {

	private static DocumentDao  documentDao = new DocumentDao();
	/**
	 * ���documentID����Module�������а�(���ظö�������5�������������
	 * @param docId
	 * @return
	 */
	private static Module getModuleByDocId(int docId){
		Module module = null;
		ModuleDocument moduleDocument = documentDao.getDocumentByID(docId);
		//���ݾɵģ�ʹ�ð��ϵ��Ĵ򿪷�ʽ
		if(null != moduleDocument.getDependFileIds() && !moduleDocument.getDependFileIds().equalsIgnoreCase("")){
			return openModule(moduleDocument);
		}
		//�����5�ĵ�
		ArrayList<Module> relaModuleList = new ArrayList<Module>();
		//�����SubModule �������������ģ��
		if("SubModule".equalsIgnoreCase(moduleDocument.getDocType())&& moduleDocument.getBelongsTo() != 0){
			ModuleDocument MainDocument = documentDao.getDocumentByID(moduleDocument.getBelongsTo());
			relaModuleList.add(openModule(MainDocument.getDocId()));
			module = Action.openModule(Action.FORMAT_YANG, moduleDocument.getDocContent(), relaModuleList);
		}
		else{
			module =openModule(docId) ;
		}
		
		return module;
	}
	
	private  static Module openModule(int docId){
		Module module = null;
		ModuleDocument moduleDocument = documentDao.getDocumentByID(docId);
		//�����5�ĵ�
		ArrayList<ModuleDocument> relationDocList = null;
		relationDocList = documentDao.getRelationDocumentByDocID(docId);
		if(relationDocList.size() == 0){
			module = Action.openModule(Action.FORMAT_YANG, moduleDocument.getDocContent(), null);
			return module;
		}else{
			ArrayList<Module> relaModuleList = new ArrayList<Module>();
			for(int i = 0 ; i < relationDocList.size() ;i++){
				module = openModule(relationDocList.get(i).getDocId());
				relaModuleList.add(module);
			}
			module =  Action.openModule(Action.FORMAT_YANG, moduleDocument.getDocContent(), relaModuleList);
		}
		return module;
	}
	//���ݾɵģ�ʹ�ð��ϵ��Ĵ򿪷�ʽ
	private  static Module openModule(ModuleDocument doc){
		Module module = null;
		String[] DependFileIdArr = doc.getDependFileIds().split(",");
		
		//�����5�ĵ�
		ArrayList<Module> relaModuleList = new ArrayList<Module>();
		for(int i = 0 ; i<DependFileIdArr.length ; i++){
			String relayId= DependFileIdArr[i];
			String[] idDetail= relayId.split("@");
			if (idDetail.length != 2){
				return null;
			}
			int relyOnDocmentId = Integer.parseInt(idDetail[0]);
			String type = idDetail[1];
			if (type.equals("pub")){
				module = openFileModule(relyOnDocmentId);
			}
			else {
				module = GetModuleByDocId(relyOnDocmentId);
			}
			
			relaModuleList.add(module);
		}
		module =  Action.openModule(Action.FORMAT_YANG, doc.getDocContent(), relaModuleList);
		return module;
	}
	//���ѹ鵵���ļ�
	public  static Module openFileModule(int fileId){
		Module module = null;
		ModuleFile file = GetModuleFileSource.getBeanByFileId(fileId);
		if (null == file){
			return null;
		}
		String dependIds = "";
		if( null != file.getDependFileIds() && !file.getDependFileIds().equalsIgnoreCase("") ){
			dependIds = file.getDependFileIds();
		}
		ArrayList<Integer> dependList = new ArrayList<Integer>();
		if(!dependIds.equalsIgnoreCase("")){
			String[] IdArr = dependIds.split(",");
			for(int i = 0 ; i < IdArr.length ; i++){
				dependList.add(Integer.parseInt(IdArr[i]));
			}
		}
		
		if(dependList.size() == 0){
			module = Action.openModule(Action.FORMAT_YANG, file.getContent(), null);
		}else{
			ArrayList<Module> relaModuleList = new ArrayList<Module>();
			for(int i = 0 ; i < dependList.size(); i++){
				module = openFileModule(dependList.get(i));
				relaModuleList.add(module);
			}
			module = Action.openModule(Action.FORMAT_YANG, file.getContent(), relaModuleList);
		}
		
		
		return module;
	}
	public static Module GetModuleByDocId(int docId){
		return getModuleByDocId(docId);
	}
	
	/**
	 * ��Session �л�õ�ǰ�û���Ϣ���Լ���ǰ�û���༭���ĵ�����
	 * @param request
	 * @return
	 * @throws ServletException
	 * @throws IOException
	 */
	private static Module getMemberData(HttpServletRequest request)throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		/**
		 * ����Ƶ������ module������Ľ�����Ŀǰ����Session��Ϊ�洢���ȴ��Ż�
		 */
		SessionObj sessionObj  = (SessionObj)request.getSession().getAttribute("sessionObj");
		Module module = sessionObj.getModule();
		if( null ==  module){
			int curDocID = sessionObj.getCurDocID();
			
			module  = getModuleByDocId(curDocID);
			//��ȡ��ǰ�ĵ���״̬
			//ModuleStatus moduleStatus = GetAuditSource.getModuleStatusByDocId(curDocID);
			ModuleDocument document   = documentDao.getDocumentByID(curDocID);
			ModuleStatus moduleStatus = ModuleStatus.getModuleStatus(document.getStatus());
			
			sessionObj.setModuleStatus(moduleStatus);
			
			sessionObj.setModule(module);
			request.getSession().setAttribute("sessionObj", sessionObj);
		}
		
		return module;
	}
	
	/**
	 * ��ȡģ����ݵ�Ψһ�ӿ�
	 * @param request
	 * @return
	 * @throws ServletException
	 * @throws IOException
	 */
	public static Module getDataRead(HttpServletRequest request)throws ServletException, IOException {
		//���ѹ鵵���ļ��д�
		if(null != request.getParameter("isFiled")){
			return GetModuleFileSource.getFiledModule(request);
		}
		
		return getMemberData(request);
	}

	/**
	 * ����ݱ��浽�ڴ��е�Ψһ�ӿ�
	 * @param request
	 * @param module
	 * @throws ServletException
	 * @throws IOException
	 */
	public static void getDataWrite(HttpServletRequest request , Module module)throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		SessionObj sessionObj = (SessionObj)request.getSession().getAttribute("sessionObj");
		sessionObj.setModule(module);
		request.getSession().setAttribute("sessionObj", sessionObj);
	}
	
	/**
	 * ��ģ�����ת��ΪXML�ĵ����־û�����ݿ���
	 * @param request
	 * @param module
	 * @throws ServletException
	 * @throws IOException
	 */
	public static void DataWriteToDB(HttpServletRequest request , Module module)throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		
		ModuleDocument mainDocument = null;
		ModuleDocument document     = new ModuleDocument();
		SessionObj sessionObj = (SessionObj)request.getSession().getAttribute("sessionObj");
		
		if(null == sessionObj){
			return;
		}
		
		Member member = sessionObj.getMember();
		//��Ӧ����ʱ�����
		if(-1 != sessionObj.curDocID){
			document = documentDao.getDocumentByID(sessionObj.curDocID);
		}
		if(module.getClass() == MainModule.class){
			document.setBelongsTo(0);            //��ģ�鲻�����κ�ģ��
			document.setDocType("MainModule");
		}else{
			SubModule subModule = (SubModule)module;
			mainDocument = documentDao.getMemberDocument(member.getMemberId(), subModule.getBelongsto().getName());
			document.setBelongsTo(mainDocument.getDocId());
			document.setDocType("SubModule");
		}
		Integer curDocID = sessionObj.getCurDocID();
		
		if(module.getRevisionsNumber()!=0){
			document.setDisplayName(module.getName()+"@"+module.getRevision(0).getName());
		}else{
			document.setDisplayName(module.getName());
		}
		
		document.setDocName(module.getName());
		document.setMemberId(member.getMemberId());
		document.setDocId(curDocID);                  //����
		YangFormatter formatter = new YangFormatter();
		formatter.setPrettyFormatter();
		document.setDocContent(module.toYANGString(formatter)); //����
		documentDao.dataSave(document);
		//��Ӧ����ʱ�����
		if(-1 == curDocID){
			document = DocDataSource.getUserDocumentByName(request, module.getName());
		}
		//���ϵ����
		dealwithRelationship(module,document.getDocId(),request);
	}
	
	private static void dealwithRelationship(Module module ,int mainDocID, HttpServletRequest request){
		Include include          = null;
		ModuleDocument relyDoc   = null;
		ModuleFile     relyFile  = null;
		Map<DocRelation,Integer> relationMap = DocDataSource.getRelationMap(mainDocID); 
		
		for(int i = 0; i < module.getIncludesNumber(); i++){
			include = module.getInclude(i);
			relyDoc =DocDataSource.getUserDocumentByName(request, include.getName());
			if(isExitIncludeRelation(relationMap,relyDoc)){
				continue;
			}
			DocDataSource.addIcludeRelation(mainDocID, relyDoc.getDocId());
		}
		
		Import import_param =  null;
		for (int i = 0; i < module.getImportsNumber(); i++) {
			import_param = module.getImport(i);
			
			
			String importName = "";
			if(null == import_param.getRevisionDate()){
				Module iModule = import_param.getEnv().getModule(import_param.getName());
				importName = import_param.getName()+"@"+iModule.getCurRevisionDate();
			}else{
				importName = import_param.getName()+"@"+import_param.getRevisionDate();
			}
			relyDoc     = DocDataSource.getUserDocumentByName(request, import_param.getName());
			if(null == relyDoc){
				relyFile = GetModuleFileSource.getBeanByFileName(importName);
				if(null != relyFile){
					DocDataSource.updateDependFileIds(mainDocID, relyFile.getFileId());
					continue;
				}
			}
			if(null == relyDoc || isExitImportRelation(relationMap , relyDoc)){
				continue;
			}
			DocDataSource.addImportRelation(mainDocID, relyDoc.getDocId());
		}
		deleteUnExitRelation(relationMap);
		deleteUnExitDepends( module , mainDocID);
	}
	
	private static boolean isExitIncludeRelation(Map<DocRelation,Integer> relationMap,ModuleDocument relyDoc){
		boolean flag =false;
		
		Set<DocRelation> relationKetSet = relationMap.keySet();
		Iterator<DocRelation> it = relationKetSet.iterator();
		DocRelation tempRelation = null;
		while(it.hasNext()){
			tempRelation = it.next();
			if(tempRelation.getRelatedDocId() == relyDoc.getDocId() && tempRelation.getRelationType().equalsIgnoreCase("include")){
				flag = true;
				relationMap.put(tempRelation, 1);//��idDelete������Ϊ1��˵�����5��ϵ��Ȼ����
				break;
			}
		}
		return flag;
	}
	
	
	private static boolean isExitImportRelation(Map<DocRelation,Integer> relationMap,ModuleDocument relyDoc){
		boolean flag =false;
		
		Set<DocRelation> relationKetSet = relationMap.keySet();
		Iterator<DocRelation> it = relationKetSet.iterator();
		DocRelation tempRelation = null;
		while(it.hasNext()){
			tempRelation = it.next();
			if(tempRelation.getRelatedDocId() == relyDoc.getDocId() && tempRelation.getRelationType().equalsIgnoreCase("import")){
				flag = true;
				relationMap.put(tempRelation, 1);//��idDelete������Ϊ1��˵�����5��ϵ��Ȼ����
				break;
			}
		}
		return flag;
	}
	/**
	 * ɾ����ڵ���5��ϵ
	 * @param relationMap
	 */
	private static void deleteUnExitRelation(Map<DocRelation,Integer> relationMap){
		Set<Map.Entry<DocRelation,Integer>> set = relationMap.entrySet();
        for (Iterator<Map.Entry<DocRelation,Integer>> it = set.iterator(); it.hasNext();) {
            Map.Entry<DocRelation,Integer> entry = (Map.Entry<DocRelation,Integer>) it.next();
            if(0 == entry.getValue() ){
            	DocDataSource.removeRelation(entry.getKey());
            }
        }
	}
	/**
	 * 
	 * @param module
	 * @param mainDocID
	 */
	private static void deleteUnExitDepends(Module module ,int mainDocID){
		ModuleDocument document = getDocumentBydocId(mainDocID);
		String dependStr = document.getDependFileIds();
		if(null == dependStr || dependStr.equalsIgnoreCase("")){
			return;
		}
		
		ArrayList<ModuleFile> fileList = GetModuleFileSource.getListByFileIds(dependStr);
		Import import_param =  null;
		String fileName     =  null; 
		String fileIdStr    =  "";
		for (int i = 0; i < module.getImportsNumber(); i++) {
			import_param = module.getImport(i);
			if(null == import_param.getRevisionDate()){
				Module iModule = import_param.getEnv().getModule(import_param.getName());
				fileName = import_param.getName()+"@"+iModule.getCurRevisionDate();
			}else{
				fileName = import_param.getName()+"@"+import_param.getRevisionDate();
			}
			//fileName = import_param.getName()+"@"+import_param.getRevisionDate();
			for (ModuleFile file : fileList) {
				if(file.getFileName().equalsIgnoreCase(fileName)){
					fileIdStr += file.getFileId()+",";
					break;
				}
			}
		}
		if(null!=fileIdStr && fileIdStr.length() > 0){
			fileIdStr = fileIdStr.substring(0,fileIdStr.length()-1);
		}
		
		document.setDependFileIds(fileIdStr);
		
		documentDao.update(document);
		
	}
	public static MainModule getMainModuleByName(HttpServletRequest request , String moduleName)throws ServletException, IOException {
		ModuleDocument document = DocDataSource.getUserDocumentByName(request, moduleName);
		if(document.getDocType().equalsIgnoreCase("SubModule")){
			return null;
		}
		return (MainModule)getModuleByDocId(document.getDocId());
	}
	
	public static Module getModuleByName(HttpServletRequest request , String moduleName)throws ServletException, IOException {
		ModuleDocument document = DocDataSource.getUserDocumentByName(request, moduleName);
		return getModuleByDocId(document.getDocId());
	}
	/**
	 * ����״̬�ַ�����
	 * @return
	 */
	public static String[] getStatusList(){
		final   String[] statusList = {"current","deprecated","obsolete","default"};
		
		return statusList;
	}
	/**
	 * ���ػ��Type����
	 * @return
	 */
	public static ArrayList<String> GetTypeList(){
		return BuiltinType.getBuiltinTypes();
	}
	
	public static String GetCurrNodeIfFeatureList(Node itemNode){
		String ifFeatureList = "";
		for(int i = 0 ; i < itemNode.getIf_featuresNumber(); i++){
			ifFeatureList +=itemNode.getIf_feature(i)+",";
		}
		if(ifFeatureList.length()>1)
			ifFeatureList = ifFeatureList.substring(0,ifFeatureList.length()-1);
		return ifFeatureList;
	}
	public static String GetAvailableIfFeatureList(Node itemNode){
		String ifFeatureList = "";
		ArrayList<String> ifFeatureAList  = null;
		Module module  = itemNode.getEnv().getCurModule();
		ifFeatureAList = module.getAvailableFeatureNames();
		if(null != ifFeatureAList){
			Iterator<String> it = ifFeatureAList.iterator();
			while(it.hasNext()){
				ifFeatureList +=it.next()+",";
			}
			ifFeatureList = ifFeatureList.substring(0,ifFeatureList.length()-1);
		}
		
		return ifFeatureList;
	}
	
	public static boolean updateDocStatus(int docId , ModuleStatus status){
		return documentDao.updateDocStatus(docId, status.getModuleStatus());
	}
	
	public static ModuleDocument getDocumentBydocId(int docId){
		return documentDao.getDocumentByID(docId);
	}
}
